package com.duojuhe.coremodule.form.service.impl;

import cn.hutool.core.map.MapUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.alibaba.fastjson.TypeReference;
import com.duojuhe.common.annotation.KeyLock;
import com.duojuhe.common.bean.UserTokenInfoVo;
import com.duojuhe.coremodule.form.enums.FormEnum;
import com.duojuhe.common.result.ErrorCodes;
import com.duojuhe.common.result.PageResult;
import com.duojuhe.common.result.ServiceResult;
import com.duojuhe.common.utils.idgenerator.UUIDUtils;
import com.duojuhe.common.utils.iputil.IPUtils;
import com.duojuhe.common.utils.jsonutils.JsonUtils;
import com.duojuhe.common.utils.page.PageHelperUtil;
import com.duojuhe.coremodule.BaseService;
import com.duojuhe.coremodule.form.entity.FormProjectResult;
import com.duojuhe.coremodule.form.entity.FormProjectSetting;
import com.duojuhe.coremodule.form.mapper.*;
import com.duojuhe.coremodule.form.pojo.project.FormProjectIdReq;
import com.duojuhe.coremodule.form.pojo.project.QueryFormProjectDetailsRes;
import com.duojuhe.coremodule.form.pojo.project.QueryFormProjectRes;
import com.duojuhe.coremodule.form.pojo.projectitem.QueryFormProjectItemRes;
import com.duojuhe.coremodule.form.pojo.projectlogic.QueryFormProjectLogicPageRes;
import com.duojuhe.coremodule.form.pojo.projectresult.*;
import com.duojuhe.coremodule.form.pojo.projectresult.report.QueryProjectResultReportDeviceRes;
import com.duojuhe.coremodule.form.pojo.projectresult.report.QueryProjectResultReportSituationRes;
import com.duojuhe.coremodule.form.pojo.projectresult.report.QueryProjectResultReportSourceRes;
import com.duojuhe.coremodule.form.pojo.projectresult.report.QueryProjectResultReportStatsRes;
import com.duojuhe.coremodule.form.pojo.projectstyle.QueryFormProjectStyleRes;
import com.duojuhe.coremodule.form.service.FormProjectResultService;
import com.duojuhe.coremodule.form.utils.handle.HandleFormUtils;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import javax.annotation.Resource;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import javax.servlet.http.HttpServletRequest;
import java.math.BigDecimal;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.Objects;

@Slf4j
@Service
public class FormProjectResultServiceImpl  extends BaseService implements FormProjectResultService {
    @Resource
    private FormProjectMapper formProjectMapper;
    @Resource
    private FormProjectResultMapper formProjectResultMapper;
    @Resource
    private FormProjectSettingMapper formProjectSettingMapper;
    @Resource
    private FormProjectLogicMapper formProjectLogicMapper;
    @Resource
    private FormProjectStyleMapper formProjectStyleMapper;
    @Resource
    private FormProjectItemMapper formProjectItemMapper;
    /**
     * 【保存】表单结果
     * @param req
     * @return
     */
    @KeyLock(lockKeyParts = "projectId")
    @Override
    public ServiceResult<String> saveFormProjectResult(SaveFormProjectResultReq req) {
        //问卷类型
        String projectType = FormEnum.FormProjectType.FORM_SURVEY_QUESTIONNAIRE.getKey();
        //项目id
        String projectId = req.getProjectId();
        QueryFormProjectRes formProject = formProjectMapper.queryFormProjectResByProjectId(projectId);
        if (formProject == null || !projectType.equals(formProject.getProjectTypeCode())) {
            return ServiceResult.fail(ErrorCodes.PARAM_ERROR);
        }
        //项目必须是发布了的
        String published = FormEnum.FormProjectStatus.FORM_PROJECT_PUBLISHED.getKey();
        if (!published.equals(formProject.getStatusCode())){
            return ServiceResult.fail(ErrorCodes.FORM_PROJECT_NO_PUBLISHED);
        }

        //检查配置
        FormProjectSetting formProjectSetting = formProjectSettingMapper.selectByPrimaryKey(projectId);
        if (formProjectSetting == null) {
            return ServiceResult.fail(ErrorCodes.PARAM_ERROR);
        }
        //检查风格
        QueryFormProjectStyleRes styleRes = formProjectStyleMapper.queryFormProjectStyleResByProjectId(projectId);
        if (styleRes == null) {
            return ServiceResult.fail(ErrorCodes.PARAM_ERROR);
        }
        //构建流程当前逻辑
        List<QueryFormProjectLogicPageRes> logicResList = formProjectLogicMapper.queryFormProjectLogicPageResByProjectId(req.getProjectId());
        String formLogicConfig = HandleFormUtils.getFormLogicConfigJsonString(logicResList);
        //项目明细集合
        PageHelperUtil.defaultOrderBy("sort asc,updateTime desc, projectId desc");
        List<QueryFormProjectItemRes> itemResList = formProjectItemMapper.queryFormProjectItemResListByProjectId(projectId);
        PageHelperUtil.clearPage();
        if (itemResList.isEmpty()){
            return ServiceResult.fail(ErrorCodes.FORM_PROJECT_NO_FORM_ITEM);
        }
        for (QueryFormProjectItemRes res:itemResList){
            HandleFormUtils.setHandleFormProjectItemRes(res);
        }
        //构建对象
        QueryFormProjectDetailsRes detailsRes = new QueryFormProjectDetailsRes();
        //项目详情
        detailsRes.setFormProjectRes(formProject);
        //项目风格详情
        detailsRes.setFormProjectStyleRes(styleRes);
        //项目明细
        detailsRes.setFormProjectItemResList(itemResList);
        String formContentConfig = JSON.toJSONString(detailsRes);

        HttpServletRequest request = ((ServletRequestAttributes) Objects.requireNonNull(RequestContextHolder.getRequestAttributes())).getRequest();
        //获取ip当前客户
        String submitIp = IPUtils.getClientIP(request);
        //当前时间
        Date nowDate = new Date();
        //当前登录人
        UserTokenInfoVo userTokenInfoVo = getCurrentLoginUserInfoDTO();
        //当前登录人id
        String userId = userTokenInfoVo.getUserId();
        //提交流水号
        String serialNumber = UUIDUtils.getSequenceNo();
        //结果对象
        FormProjectResult projectResult = new FormProjectResult();
        projectResult.setId(UUIDUtils.getUUID32());
        projectResult.setSerialNumber(serialNumber);
        projectResult.setCreateTime(nowDate);
        projectResult.setUpdateTime(nowDate);
        projectResult.setCreateUserId(userId);
        projectResult.setUpdateUserId(userId);
        projectResult.setSubmitUserId(userId);
        projectResult.setCreateDeptId(userTokenInfoVo.getCreateDeptId());
        projectResult.setTenantId(userTokenInfoVo.getTenantId());
        projectResult.setProjectId(projectId);
        projectResult.setProjectKey(formProject.getProjectKey());
        projectResult.setOriginalData(JsonUtils.objToJson(req.getOriginalData()));
        projectResult.setProcessData(JsonUtils.objToJson(req.getProcessData()));
        projectResult.setSubmitIp(submitIp);
        projectResult.setSubmitOs(req.getSubmitOs());
        projectResult.setSubmitBrowser(req.getSubmitBrowser());
        projectResult.setSubmitUa(JsonUtils.objToJson(req.getSubmitUa()));
        projectResult.setCompleteTime(req.getCompleteTime());
        projectResult.setFormLogicConfig(formLogicConfig);
        projectResult.setFormContentConfig(formContentConfig);
        projectResult.setSubmitSource(userTokenInfoVo.getUserLoginSource());
        formProjectResultMapper.insertSelective(projectResult);
        return ServiceResult.ok(serialNumber);
    }
    /**
     * 【修改】表单结果
     * @param req
     * @return
     */
    @KeyLock(lockKeyParts = "id")
    @Transactional(rollbackFor = Exception.class)
    @Override
    public ServiceResult<String> updateFormProjectResult(UpdateFormProjectResultReq req) {
        FormProjectResult projectResultOld = formProjectResultMapper.selectByPrimaryKey(req.getId());
        if (projectResultOld==null){
            return ServiceResult.fail(ErrorCodes.PARAM_ERROR);
        }
        //当前时间
        Date nowDate = new Date();
        //当前登录人
        UserTokenInfoVo userTokenInfoVo = getCurrentLoginUserInfoDTO();
        //当前登录人id
        String userId = userTokenInfoVo.getUserId();
        //提交流水号
        String serialNumber = projectResultOld.getSerialNumber();
        //结果对象
        FormProjectResult projectResult = new FormProjectResult();
        projectResult.setId(projectResultOld.getId());
        projectResult.setUpdateTime(nowDate);
        projectResult.setUpdateUserId(userId);
        projectResult.setOriginalData(JsonUtils.objToJson(req.getOriginalData()));
        projectResult.setProcessData(JsonUtils.objToJson(req.getProcessData()));
        formProjectResultMapper.updateByPrimaryKeySelective(projectResult);
        return ServiceResult.ok(serialNumber);
    }

    /**
     * 【彻底删除】删除表单结果记录
     * @param req
     * @return
     */
    @Override
    public ServiceResult deleteFormProjectResultById(FormProjectResultIdReq req) {
        FormProjectResult projectResult = formProjectResultMapper.selectByPrimaryKey(req.getId());
        if (projectResult==null){
            return ServiceResult.fail(ErrorCodes.PARAM_ERROR);
        }
        formProjectResultMapper.deleteByPrimaryKey(req.getId());
        return ServiceResult.ok(ErrorCodes.SUCCESS);
    }

    /**
     * 【分页查询】根据条件查询表单项目提交结果集合
     * @param req
     * @return
     */
    @Override
    public ServiceResult<PageResult<List<QueryFormProjectResultPageRes>>> queryFormProjectResultPageResList(QueryFormProjectResultPageReq req) {
        PageHelperUtil.orderByAndStartPage(req, "updateTime desc, id desc");
        //最终拼接sql字符串
        StringBuilder sqlString = new StringBuilder();
        if (ObjectUtil.isNotNull(req.getExtParamsMap())) {
            req.getExtParamsMap().keySet().forEach(item -> {
                String comparison = MapUtil.getStr(req.getExtComparisonsMap(), item);
                QueryFormProjectResultPageReq.QueryComparison queryComparison = QueryFormProjectResultPageReq.QueryComparison.get(comparison);
                Object value = req.getExtParamsMap().get(item);
                if (queryComparison == QueryFormProjectResultPageReq.QueryComparison.LIKE) {
                    value="'%"+value+"%'";
                }
                sqlString.append(StrUtil.format("and original_data ->'$.{}' {} {} ", item, queryComparison.getKey(), value));
            });
        }
        List<QueryFormProjectResultPageRes> list = formProjectResultMapper.queryFormProjectResultPageResList(req,sqlString.toString());
        for (QueryFormProjectResultPageRes res:list){
            //填写结果处理后的数据
            if (StringUtils.isNotBlank(res.getProcessData())){
                res.setProcessDataMap(JSONObject.parseObject(res.getProcessData(), Map.class));
            }
            //提交用户客户端信息
            if (StringUtils.isNotBlank(res.getSubmitUa())){
                res.setSubmitUaMap(JSONObject.parseObject(res.getSubmitUa(), Map.class));
            }
        }
        return PageHelperUtil.returnServiceResult(req, list);
    }

    /**
     * 【查询项目收集设备分析】根据项目id查询提交来源统计分析
     * @param req
     * @return
     */
    @Override
    public ServiceResult<List<QueryProjectResultReportDeviceRes>> queryProjectResultReportDeviceResByProjectId(FormProjectIdReq req) {
        return ServiceResult.ok(formProjectResultMapper.queryProjectResultReportDeviceResByProjectId(req.getProjectId()));
    }

    /**
     * 【项目收集情况 按周查看】根据项目id查询项目收集情况 按周查看分析
     * @param req
     * @return
     */
    @Override
    public ServiceResult<List<QueryProjectResultReportSituationRes>> queryProjectResultReportSituationResByProjectId(FormProjectIdReq req) {
        return ServiceResult.ok(formProjectResultMapper.queryProjectResultReportSituationResByProjectId(req.getProjectId()));
    }
    /**
     * 【查询项目收集来源分析】根据项目id查询项目收集来源分析
     * @param req
     * @return
     */
    @Override
    public ServiceResult<List<QueryProjectResultReportSourceRes>> queryProjectResultReportSourceResByProjectId(FormProjectIdReq req) {
        return ServiceResult.ok(formProjectResultMapper.queryProjectResultReportSourceResByProjectId(req.getProjectId()));
    }


    /**
     * 【查询项目收集信息】根据项目id查询项目收集信息
     * @param req
     * @return
     */
    @Override
    public ServiceResult<QueryProjectResultReportStatsRes> queryProjectResultReportStatsResByProjectId(FormProjectIdReq req) {
        QueryProjectResultReportStatsRes statsRes = formProjectResultMapper.queryProjectResultReportStatsResByProjectId(req.getProjectId());
        if (statsRes==null){
            return ServiceResult.fail(ErrorCodes.PARAM_ERROR);
        }
        BigDecimal rate = BigDecimal.ZERO;
        if (statsRes.getHitsCount()!=null&&statsRes.getHitsCount()>0){
            rate = BigDecimal.valueOf(statsRes.getCompleteCount()).divide(BigDecimal.valueOf(statsRes.getHitsCount()),2,BigDecimal.ROUND_HALF_UP);
        }
        if (statsRes.getAvgCompleteTime()!=null){
            statsRes.setAvgCompleteTime(statsRes.getAvgCompleteTime().divide(new BigDecimal("1000"),2,BigDecimal.ROUND_HALF_UP));
        }
        statsRes.setCompleteRate(rate);
        return ServiceResult.ok(statsRes);
    }

    /**
     * 【查询问卷记录编辑初始值】根据记录id查询查询记录编辑初始值明细
     * @param req
     * @return
     */
    @Override
    public ServiceResult<QueryFormProjectResultDetailsEditRes> queryFormProjectResultDetailsEditResById(FormProjectResultIdReq req) {
        //记录ID
        String id = req.getId();
        FormProjectResult formProjectResult =  formProjectResultMapper.selectByPrimaryKey(id);
        if (formProjectResult==null){
            return ServiceResult.fail(ErrorCodes.PARAM_ERROR);
        }
        QueryFormProjectResultDetailsEditRes detailsRes = new QueryFormProjectResultDetailsEditRes();
        detailsRes.setOriginalData(formProjectResult.getOriginalData());
        detailsRes.setProcessData(formProjectResult.getProcessData());
        if (StringUtils.isNotBlank(formProjectResult.getFormLogicConfig())){
            List<QueryFormProjectLogicPageRes> logicPageResList = JSON.parseObject(formProjectResult.getFormLogicConfig(),new TypeReference<List<QueryFormProjectLogicPageRes>>(){});
            detailsRes.setLogicPageResList(logicPageResList);
        }
        if (StringUtils.isNotBlank(formProjectResult.getFormContentConfig())){
            QueryFormProjectDetailsRes projectDetailsRes = JSON.parseObject(formProjectResult.getFormContentConfig(),new TypeReference<QueryFormProjectDetailsRes>(){});
            detailsRes.setFormProjectItemResList(projectDetailsRes.getFormProjectItemResList());
            detailsRes.setFormProjectRes(projectDetailsRes.getFormProjectRes());
            detailsRes.setFormProjectStyleRes(projectDetailsRes.getFormProjectStyleRes());
        }
        return ServiceResult.ok(detailsRes);
    }

}
